#include <Windows.h>

#define DWORD_HIGH (UINT_MAX + 1)
#define SIZE_OF_BUFFER (100 * 1024 * 1024) // 100 MB

// Class for file IO via file mapping. Each instance of class works with one
// file at the time. 
class FileIO {
 public:
  
  // Creates an instance of class with pre-loaded file. All arguments are
  // similar to arguments of loadFile function
  FileIO(wchar_t* filename = NULL, bool output = false, DWORD dw_file_size_high = 0,
         DWORD dw_file_size_low = 0);

  ~FileIO();

  // Specifies file to work with and creates a handle. Returns false on failure 
  // Set otput as true to allow output. In case of allowed output, file size
  // must be specified. If file is opened only for input, size will be calculated
  // automaticly
  bool loadFile(wchar_t* filename, bool output, DWORD dw_file_size_high = 0,
         DWORD dw_file_size_low = 0);

  // Creates a pointer to memory for output and/or input to file. If the size
  // of the file is more than maximum allowed buffer size, only a maximum 
  // allowed buffer will be mapped. The next part of file will be mapped on the
  // next call of the function.
  char* getNextMap(bool* is_last_map = NULL);

  // Get size of current loaded file
  DWORD getFileSize(DWORD* dw_file_size_high);
  
 private:
  // Current loaded file
  wchar_t* file_;

  // Handle for current loaded file and its map
  HANDLE _file, file_map_;

  // Current position in file
  DWORD dw_file_offset_high_, dw_file_offset_low_;

  // Size of loaded file
  DWORD dw_file_size_high_, dw_file_size_low_;

  // True if output is allowed for current loaded file
  bool output_;

  // Creates handle for file. If output is false, file is opened only for input.
  // Otherwise, it's open both for input and output. In this case, if file does
  // not exist it would be created.
  HANDLE openFile();

  // Creates handle for file mapping.
  HANDLE createMapOfFile();  
  
  // Increase current low and high offsets
  void increaseOffsets(SIZE_T size);
};